#ifndef SKYROAD_BIN_IARCHIVE_H_
#define SKYROAD_BIN_IARCHIVE_H_

#include <string>
#include <algorithm>
#include <vector>
#include <boost/array.hpp>
#include <skyroad/archive/nvp.hpp>
#include <skyroad/detail/config.hpp>

class SKYROAD_DECL bin_iarchive
{
    public:
    bin_iarchive(const unsigned char* first, const unsigned char* last, int version) 
                 : m_data(first), m_first(first), m_last(last), m_version(version), m_error(false) 
    {

    }

    bin_iarchive(const unsigned char* first, std::size_t length, int version) 
    : m_data(first), m_first(first), m_last(first+length), m_version(version), m_error(false) 
    {
    }

    template <typename T, std::size_t N>
    void read_array(boost::array<T, N>& a) 
    {
        if (m_error)
        {
            return;
        }
        read(a);
    }

    void read(unsigned char& c);

    void read(unsigned short& s);

    void read(unsigned long& l);

    void read(std::string& s);

    void read(std::wstring& s);

    void read(unsigned __int64& i64);

    void read(float& f);

    void read(unsigned char* buffer, std::size_t count);

    template <typename T>
    void read(std::vector<T>& v)
    {
        unsigned short size;
        read(size);
        v.resize(size);
        for (int i = 0; i < size; i++)
        {
	        serialize(*this, v[i], m_version);
        }
    }

    template <typename T, std::size_t N>
    void read(boost::array<T, N>& a) 
    {
        if (m_error)
        {
            return;
        }
        read((unsigned char*)&a[0], sizeof(T)*N);
    }

    const unsigned char* begin() { return m_first; }

    const unsigned char* end() { return m_last; }

    void seek(const unsigned char* pos) { m_first = pos; }

    const unsigned char* m_data;
    const unsigned char* m_first;
    const unsigned char* m_last;
    int m_version;
    bool m_error;
};


template <class T>
bin_iarchive& operator &(bin_iarchive& in, std::vector<T>& value)
{
    in.read(value);
    return in;
}

template <typename T, std::size_t N>
bin_iarchive& operator &(bin_iarchive& in, boost::array<T,N>& value)
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, std::string& value) 
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, std::wstring& value) 
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, unsigned char& value)
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, unsigned short& value)
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, unsigned long& value) 
{
    in.read(value);
    return in;
}

inline bin_iarchive& operator &(bin_iarchive& in, unsigned __int64& value)
{
    in.read(value);
    return in;
}

template <typename Value>
inline bin_iarchive& operator &(bin_iarchive& in, nvp<Value> nv) 
{
    in.read(*nv.second);
    return in;
}

#endif
